package com.lap.auth.application.authentication;

import com.lap.auth.application.authentication.assembler.AuthAssembler;
import com.lap.auth.application.authentication.command.LoginCmd;
import com.lap.auth.application.authentication.dto.TokenDto;
import com.lap.auth.application.authentication.dto.UserDto;
import com.lap.auth.domain.shared.ports.JwtService;
import com.lap.auth.domain.shared.errors.LoginError;
import com.lap.auth.domain.shared.errors.UserError;
import com.lap.auth.domain.shared.exception.ExpiredException;
import com.lap.auth.domain.user.User;
import com.lap.auth.domain.user.repository.UserRepository;
import com.lap.framework.exception.BizException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class AuthQueryService {

  private final AuthAssembler assembler;
  private final JwtService jwtService;
  private final UserRepository userRepository;
  private final PasswordEncoder passwordEncoder;

  public TokenDto login(LoginCmd cmd) {
    User user =
        userRepository
            .findByUsername(cmd.getUsername())
            .orElseThrow(() -> BizException.newBiz(UserError.LOGIN_FAIL));
    user.assertUserActive();

    if (!passwordEncoder.matches(cmd.getPassword(), user.getPassword())) {
      throw BizException.newBiz(UserError.LOGIN_FAIL);
    }

    String token = jwtService.generateToken(user.getId());
    return TokenDto.builder()
        .userId(user.getId())
        .username(user.getUsername())
        .fullName(user.getFullName())
        .deptId(user.getOrgId())
        .accessToken(token).build();
  }

  public UserDto validateToken(String token) {
    try {
      Integer userId = jwtService.validateJwt(token);
      User user = userRepository.findById(userId)
          .orElseThrow(() -> BizException.newBiz(UserError.USER_NOT_FOUND));
      return assembler.toDto(user);
    } catch (ExpiredException e) {
      throw BizException.newBiz(LoginError.LOGIN_EXPIRED);
    } catch (Exception e) {
      throw BizException.newBiz(LoginError.LOGIN_TOKEN_ERROR);
    }
  }
}
